package com.dongnao.network.netty_websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;


/**
 * 通过WebSocket编程实现服务器和客户端长连接
 * 1) Http协议是无状态的，浏览器和服务器间的请求响应一次，下一次会重新创建连接.
 * 2)要求:实现基于webSocket 的长连接的全双工的交互
 * 3)改变Http协议多次请求的约束，实现长连接了，服务器可以发送消息给浏览器
 * 4)客户端浏览器和服务器端会相互感知，比如服务器关闭了，浏览器会感知，同样浏览器关闭了，服务器会感知
 */
public class MyServer {

    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //因为是http协议，所以添加http协议的编码解码器
                            pipeline.addLast(new HttpServerCodec());
                            //它主要用于处理分块写入（chunked write）的场景，特别是在写入大文件或大数据流时，
                            //可以将数据分成一系列的块进行异步写入，以避免一次性写入过大的数据导致内存占用过高
                            pipeline.addLast(new ChunkedWriteHandler());

                            //1. http数据在传输过程中是分段，HttpObjectAggregator就是可以将多个段聚
                            //2．这就就是为什么，当浏览器发送大量数据时，就会发出多次http请求
                            pipeline.addLast(new HttpObjectAggregator(8192));

                            //WebSocketServerProtocolHandler核心功能是将 http协议升级为 ws协议，保持长连接
                            pipeline.addLast(new WebSocketServerProtocolHandler("/hello2"));

                            //自定义处理器
                            pipeline.addLast(new MyWebSocketHandler());
                        }
                    });

            ChannelFuture channelFuture = bootstrap.bind(8899).sync();
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if (channelFuture.isSuccess()) {
                        System.out.println("服务器启动成功");
                    }
                }
            });
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
